﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using SunrayEngine.Threading;

namespace SunrayEngine.Managers
{
    /// <summary>
    /// The SunRay Engine draw manager that handels all the ingame drawing.
    /// </summary>
    public class DrawManager
    {
        #region fields
        private MultiThreadInvoker workHandler; //The handler for all worker threads.
        private GameComponentCollection components; //Refed from the SRMain and handels all component updateing.
        private IEnumerable<DrawableGameComponent> drawableComponents; //Components that can be updated.
        #endregion

        #region properties
        /// <summary>
        /// Check with this item if its safe to resume the main thread.
        /// </summary>
        public object Locker { get; protected set; }

        /// <summary>
        /// Returns the ammount of currently active threads.
        /// </summary>
        public int ActiveThreads { get { return workHandler.ActiveThreads; } }
        #endregion

        #region initialization
        public DrawManager(Game game, int workerThreads)
        {
            workHandler = new MultiThreadInvoker(workerThreads);

            components = game.Components;
            getDrawableComponents();

            components.ComponentAdded += (s, e) => { getDrawableComponents(); };
            components.ComponentRemoved += (s, e) => { getDrawableComponents(); };
        }
        #endregion

        #region methods
        /// <summary>
        /// Draws the manager and with it all game components.
        /// If you use this remove base.Draw(GameTime) from the main class of the game.
        /// </summary>
        /// <param name="gameTime"></param>
        public void Draw(GameTime gameTime)
        {
            //Hijack the games components and draw them in the work handler.
            foreach (var component in drawableComponents)
                workHandler.Queue(new Action(() => { component.Draw(gameTime); }));
        }

        public void DisposeThreads()
        {
            workHandler.Dispose();
        }

        private void getDrawableComponents()
        {
            //Get a collection of the updateabel components from the Component collection.
            drawableComponents = (from c in components where c is DrawableGameComponent select c as DrawableGameComponent);
        }
        #endregion
    }
}
